package org.dandsoft.blackbox.labs.snn;


import java.util.Hashtable;

/**
 * User: dvilyuzhanin
 * Date: 22.01.2009 0:48:56
 * <p/>
 * K - определяет фронт.
 * Если K < 1, то фронт сужается
 * Если K = 1, то фронт стабилен
 * Если K > 1, то фронт расширяется
 * <p/>
 * Nd = K * Ns
 * <p/>
 * Nmin определяет Ns(0) - начальное число нейронов в самом первом исходящем слое.
 * Ns(t) - определяет исходные значения для шага моделирования в момент времени t
 * K(t) - определяет тип фронта и соотношение между слоями.
 * S(t) - определялется из диапазона [Nd(t); Nd(t) * Ns(t)]
 * <p/>
 * Параметры моделирования
 * 1) K = {k(1), k(2), ... } - последовательность козфициентов изменения фронта. Определяется по определенным
 * закономерностям. Может выполнятся до начала экспиремента. Посути определяет тестовые ситуации.
 * <p/>
 * 2) S - определяется для каждого шага отдельно. Выбирается по какой-либо закономерности из диапазона
 * [k(t) * Ns(t), k(t) * Ns(t)^2]. Для вычисления S вводим коэфициент связности C. Это процентное соотношение
 * между k(t) * Ns(t) и k(t) * Ns(t) ^ 2
 * <p/>
 * len(t) = k(t) * Ns * (Ns - 1)
 * s(t) = C * len(t) / 100 + k(t) * Ns(t)
 * <p/>
 * <p/>
 * Процесс моделирования:
 * Для момента времени t
 * 1) Ns(t) = Nd(t - 1)
 * 2) k(t) из K
 * 3) s(t) = C * len(t) / 100 + k(t) * Ns(t); len(t) = k(t) * Ns * (Ns - 1);
 * 4) Nd(t) = k(t) * Ns(t)
 * <p/>
 * Sns - число выходных синапсов у нейрона с слое источнике
 * Snd - число входных синапсов в слое приемнике
 * <p/>
 * Sns = S \ Ns
 * Если S > Snd,
 * то Snd = (S - Nd) \ Nd + 1
 * иначе Snd = 1
 */
public class LoadingModel {

    private double frontSize;
    private int sourceNeuronsCount;
    private int connectivityLevel;

    public synchronized int countSourceNeuronSynapses() {
        return (int) Math.ceil((double) countSynapses() / (double) getSourceNeuronsCount());
    }

    public synchronized int countDestinationNeuronSynapses() {
        int countDestinationNeurons = countDestinationNeurons();
        return (int) Math.ceil((countSynapses() - countDestinationNeurons) / countDestinationNeurons) + 1;
    }

    /**
     * Ns(t) = Nd(t - 1)
     */
    public synchronized int next() {
        return sourceNeuronsCount = countDestinationNeurons();
    }

    /**
     * Nd(t) = k(t) * Ns(t)
     *
     * @return
     */
    public synchronized int countDestinationNeurons() {
        return (int)Math.round (sourceNeuronsCount * frontSize);
    }

    /**
     * s(t) = C * len(t) / 100 + k(t) * Ns(t); len(t) = k(t) * Ns * (Ns - 1);
     * TODO: умножение приводит к переполнению при вычислении длины диапазона. Необходимы преобразования
     * TODO: что бы избежать переполнения
     * @return
     */
    public synchronized int countSynapses() {
        int destNeurons = countDestinationNeurons();
        int length = (int) ((long)destNeurons * (long)sourceNeuronsCount - destNeurons);
        return (int) (connectivityLevel * length / 100D + destNeurons);
    }


    public synchronized double getFrontSize() {
        return frontSize;
    }

    public synchronized void setFrontSize(double frontSize) {
        this.frontSize = frontSize;
    }

    public synchronized int getSourceNeuronsCount() {
        return sourceNeuronsCount;
    }

    public synchronized void setSourceNeuronsCount(int sourceNeuronsCount) {
        this.sourceNeuronsCount = sourceNeuronsCount;
    }

    public synchronized int getConnectivityLevel() {
        return connectivityLevel;
    }

    public synchronized void setConnectivityLevel(int connectivityLevel) {
        this.connectivityLevel = connectivityLevel;
    }
}
